﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PageController.cs" company="ecblog.codeplex.com">
//   emrecoskun.net - ibrahimatay.com
// </copyright>
// <summary>
//   The page controller
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace EcBlog.Areas.Admin.Controllers
{
    using System;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Web.Mvc;

    using EcBlog.Admin.Models;
    using EcBlog.Data;
    using EcBlog.Models;
    using EcBlog.Properties;

    using Elmah;

    using Telerik.Web.Mvc;
    using Telerik.Web.Mvc.Extensions;

    /// <summary>
    /// The page controller 
    /// </summary>
    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
#if !(DEBUG)
    [Filters.Authorize(PortalRole.Admin)]
#endif
    public class PageController : Controller
    {
        #region ctor

        private readonly IEcUnitOfWork unitOfWork;

        /// <summary>
        /// Initializes a new instance of the <see cref="PageController"/> class.
        /// </summary>
        /// <param name="unitOfWork">The unit of work.</param>
        [ImportingConstructor]
        public PageController(IEcUnitOfWork unitOfWork)
        {
            this.unitOfWork = unitOfWork;
        }

        #endregion

        #region Core Action Methods

        /// <summary>
        /// Gets the index view.
        /// </summary>
        /// <returns>The indes view.</returns>
        public ActionResult Index()
        {
            this.AddDefaultValuesToViewData();
            return this.View();
        }

        /// <summary>
        /// Get the new page view.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns>
        /// The new page view
        /// </returns>
        public ActionResult NewPage(long? id)
        {
            var viewModel = id.HasValue
                                ? this.unitOfWork.PageRepository.GetById(id)
                                : new Page { Published = DateTime.Now };
            this.AddDefaultValuesToViewData();
            return this.View(viewModel);
        }

        /// <summary>
        /// News the page.
        /// </summary>
        /// <param name="currentPage">The current page.</param>
        /// <returns>The page</returns>
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult NewPage(Page currentPage)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    if (currentPage.PageId == 0)
                    {
                        currentPage.Created = DateTime.Now;
                        this.unitOfWork.PageRepository.Create(currentPage);                       
                    }
                    else
                    {
                        var created =
                            this.unitOfWork.PageRepository
                                           .Get()
                                           .Where(c => c.PageId == currentPage.PageId)
                                           .Select(c => c.Created).First();
                        currentPage.Created = created;
                        this.unitOfWork.PageRepository.Update(currentPage);
                    }

                    this.unitOfWork.Save();
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, currentPage.Title, e.Message));
                }
            }

            return this.RedirectToAction("NewPage", new { id = currentPage.PageId, area = "Admin" });
        }

        /// <summary>
        /// Previews the specified page id.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <returns>the specified page</returns>
        public ActionResult Preview(int pageId)
        { 
            return this.RedirectToAction("DynamicPageById", "Blog", new { area = string.Empty, pageId });
        } 
        #endregion

        #region AJAX Master Page Grid Action Methods

        /// <summary>
        /// Gets the page list.
        /// </summary>
        /// <param name="command">The command.</param>
        /// <returns>The page list</returns>
        [GridAction(EnableCustomBinding = true)]
        public ActionResult PageList(GridCommand command = null)
        {
            if (command == null)
            {
                command = new GridCommand();
            }

            var list = this.unitOfWork.PageRepository.Get();
            return this.View(list.ToGridModel(command.Page, command.PageSize, command.SortDescriptors, command.FilterDescriptors, command.GroupDescriptors)); 
        }

        /// <summary>
        /// Inserts the specified currentpage.
        /// </summary>
        /// <param name="currentpage">The currentpage.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult Insert(Page currentpage, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    currentpage.Created = DateTime.Now;
                    this.unitOfWork.PageRepository.Create(currentpage);
                    this.unitOfWork.Save();
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, currentpage.Title, e.Message));
                }
            }

            return this.PageList(command);
        }

        /// <summary>
        /// Updates the specified currentpage.
        /// </summary>
        /// <param name="currentpage">The currentpage.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult Update(Page currentpage, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    var created =
                        this.unitOfWork.PageRepository.Get().Where(c => c.PageId == currentpage.PageId).Select(
                            c => c.Created).First();
                    currentpage.Created = created;
                    this.unitOfWork.PageRepository.Update(currentpage);
                    this.unitOfWork.Save();
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, currentpage.Title, e.Message));
                }
            }

            return this.PageList(command);
        }

        /// <summary>
        /// Deletes the specified page id.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult Delete(long pageId, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    if (this.unitOfWork.CommentRepository.Get().Any(c => c.PageId == pageId)
                        || this.unitOfWork.TagRepository.Get().Any(c => c.Pages.Any(l => l.PageId == pageId)))
                    {
                        var title = this.unitOfWork.PageRepository.GetById(pageId).Title;
                        this.Response.StatusCode = 500;
                        this.Response.AppendHeader("message", string.Format(ModelLocalization.DeleteSubItemFirst, title));
                    }
                    else
                    {
                        this.unitOfWork.PageRepository.Delete(pageId);
                        this.unitOfWork.Save();
                    }
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, pageId, e.Message));
                }
            }

            return this.PageList(command);
        }

        #endregion

        #region AJAX Comment Detail Grid Action Methods

        /// <summary>
        /// Gets the page comments.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [GridAction(EnableCustomBinding = true)]
        public ActionResult GetPageComments(long pageId, GridCommand command = null)
        {
            if (command == null)
            {
                command = new GridCommand();
            }

            var list = this.unitOfWork.CommentRepository.Get().Where(c => c.PageId == pageId);
            return
                this.View(
                    list.ToGridModel(
                        command.Page,
                        command.PageSize,
                        command.SortDescriptors,
                        command.FilterDescriptors,
                        command.GroupDescriptors));
        }

        /// <summary>
        /// Inserts the page comment.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="comment">The comment.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult InsertPageComment(long pageId, Comment comment, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    comment.PageId = pageId;
                    comment.Created = DateTime.Now;
                    this.unitOfWork.CommentRepository.Create(comment);
                    this.unitOfWork.Save();
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, comment.CommentHtml, e.Message));
                }
            }

            return this.GetPageComments(pageId, command);
        }

        /// <summary>
        /// Updates the page comment.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="comment">The comment.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult UpdatePageComment(long pageId, Comment comment, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    var created =
                        this.unitOfWork.CommentRepository.Get().Where(c => c.CommentId == comment.CommentId).Select(
                            c => c.Created).First();
                    comment.Created = created;
                    comment.PageId = pageId;
                    this.unitOfWork.CommentRepository.Update(comment);
                    this.unitOfWork.Save();

                    // TODO
                    // if (comment.IsPublished) SendAlertMails(pageId, comment.CommentHtml); 
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, comment.CommentHtml, e.Message));
                }
            }

            return this.GetPageComments(pageId, command);
        }

        /// <summary>
        /// Deletes the page comment.
        /// </summary>
        /// <param name="commentId">The comment id.</param>
        /// <param name="pageId">The page id.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult DeletePageComment(long commentId, long pageId, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    this.unitOfWork.CommentRepository.Delete(commentId);
                    this.unitOfWork.Save();
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, commentId, e.Message));
                }
            }

            return this.GetPageComments(pageId, command);
        }

        #endregion

        #region AJAX Tag Detail Grid Action Methods

        /// <summary>
        /// Gets the page tags.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [GridAction(EnableCustomBinding = true)]
        public ActionResult GetPageTags(long pageId, GridCommand command = null)
        {
            if (command == null)
            {
                command = new GridCommand();
            }

            var list =
                this.unitOfWork.PageRepository.Get(c => c.Tags).Where(c => c.PageId == pageId).SelectMany(c => c.Tags).Select(c => new PageTag { TagId = c.TagId });
                    
            return
                this.View(
                    list.ToGridModel(
                        command.Page,
                        command.PageSize,
                        command.SortDescriptors,
                        command.FilterDescriptors,
                        command.GroupDescriptors));
        }

        /// <summary>
        /// Inserts the page tag.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="tagId">The tag id.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult InsertPageTag(long pageId, long tagId, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    if (!this.unitOfWork.TagRepository.Get().Any(c => c.TagId == tagId && c.Pages.Any(l => l.PageId == pageId)))
                    {
                        var page = this.unitOfWork.PageRepository.Get(c => c.Tags).First(c => c.PageId == pageId);
                        var tag = this.unitOfWork.TagRepository.Get(c => c.Pages).First(c => c.TagId == tagId);
                        page.Tags.Add(tag);

                        this.unitOfWork.Save();
                    }
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, tagId, e.Message));
                }
            }

            return this.GetPageTags(pageId, command);
        }

        /// <summary>
        /// Deletes the page tag.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        /// <param name="tagId">The tag id.</param>
        /// <param name="command">The command.</param>
        /// <returns>The index view</returns>
        [HttpPost]
        [GridAction(EnableCustomBinding = true)]
        [ValidateInput(false)]
        public ActionResult DeletePageTag(long pageId, long tagId, GridCommand command = null)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    var page = this.unitOfWork.PageRepository.Get(c => c.Tags).First(c => c.PageId == pageId);
                    var tag = this.unitOfWork.TagRepository.GetById(tagId);
                    page.Tags.Remove(tag);
                    this.unitOfWork.Save();
                }
                catch (Exception e)
                {
                    ErrorSignal.FromCurrentContext().Raise(e);
                    this.Response.StatusCode = 500;
                    this.Response.AppendHeader(
                        "message", string.Format(ModelLocalization.SaveUnitOfWorkError, tagId, e.Message));
                }
            }

            return this.GetPageTags(pageId, command);
        }

        #endregion

        #region AJAX Support Methods

        /// <summary>
        /// Checks the duplicate slug.
        /// </summary>
        /// <param name="slug">The slug.</param>
        /// <param name="pageId">The page id.</param>
        /// <returns>The index view</returns>
        public ActionResult CheckDuplicateSlug(string slug, long pageId)
        {
            var validateTitle =
                !this.unitOfWork.PageRepository.Get().Any(
                    c => c.PageId != pageId && c.Slug.ToLower() == slug.ToLower());
            return this.Json(validateTitle, JsonRequestBehavior.AllowGet);
        }
        #endregion

        #region disbose

        /// <summary>
        /// Releases unmanaged resources and optionally releases managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            this.unitOfWork.Dispose();
            base.Dispose(disposing);
        }

        #endregion

        #region Privates
        private void AddDefaultValuesToViewData()
        {
            var layouts = this.unitOfWork.LayoutRepository.Get().Select(c => new { Id = c.LayoutId, c.Name }).ToList();
            var tags = this.unitOfWork.TagRepository.Get().Select(c => new { Id = c.TagId, Name = c.TagName }).ToList();

            this.ViewData["layoutlist"] = layouts;
            this.ViewData["taglist"] = tags;
        } 
        #endregion
    }
}
